package com.shengqin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shengqin.calculate.data.CalculateSummaryModel;
import com.shengqin.common.pojo.CommonPage;
import com.shengqin.config.model.TestProjectConfig;
import com.shengqin.entity.*;
import com.shengqin.mapper.SummaryResultMapper;
import com.shengqin.pojo.plan.PlanQueryParam;
import com.shengqin.pojo.summary.CountModel;
import com.shengqin.pojo.summary.SummaryModel;
import com.shengqin.pojo.summary.SummaryQueryParam;
import com.shengqin.service.*;
import com.shengqin.utils.GradeUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class SummaryResultServiceImpl extends ServiceImpl<SummaryResultMapper, SummaryResult> implements ISummaryResultService {

    private static final BigDecimal percent = new BigDecimal("100");
    private static final BigDecimal BEST_SCORE = new BigDecimal("90");
    private static final BigDecimal WELL_SCORE = new BigDecimal("80");
    private static final BigDecimal PASS_SCORE = new BigDecimal("60");
    private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Resource
    private IPlanStudentService planStudentService;
    @Resource
    private ISchoolService schoolService;
    @Resource
    private TestProjectConfig testProjectConfig;
    @Resource
    private IPlanService planService;
    @Resource
    private SysHealthProjectService projectService;
    @Resource
    private ITotalScoreStandardService totalScoreStandardService;
    @Resource
    @Lazy
    private IPlanApplyProjectService planApplyProjectService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean singleSummaryResult(CalculateSummaryModel model) {
        Integer schoolId = model.getTestResultList().get(0).getSchoolId();
        School school = schoolService.getById(schoolId);
        List<SummaryResult> summaryResultList = new ArrayList<>();
        Plan plan = model.getPlan();

        List<String> studyCodes = new ArrayList<>();
        studyCodes.add(model.getStudyCode());

        List<TotalScoreStandard> totalScoreStandards = totalScoreStandardService.listByTemplateId(plan.getTemplateId());
        List<PlanStudent> studentList = planStudentService.queryByPlanIdAndStudyCodes(plan.getId(), studyCodes);
        Map<String, PlanStudent> studentMap = studentList.stream().collect(Collectors.toMap(PlanStudent::getStudyCode, s -> s));
        List<PlanApplyProject> planApplyProjects = planApplyProjectService.queryByPlanIdAndStudyCodes(plan.getId(),studyCodes);

        List<SummaryResult> oldSummaryResult = selectByPlanIdAndStudyCodes(plan.getId(), studyCodes);
        Map<String, SummaryResult> summaryResultMap = oldSummaryResult.stream().collect(Collectors.toMap(SummaryResult::getStudyCode, s -> s));

        PlanStudent student = studentMap.getOrDefault(model.getStudyCode(), null);
        SummaryResult summaryResult = summaryResultMap.getOrDefault(model.getStudyCode(), new SummaryResult());
        if (student != null) {
            String prjNames = "";
            if(!CollectionUtils.isEmpty(planApplyProjects)){
                prjNames = planApplyProjects.get(0).getProjectNames();
            } else {
                prjNames = testProjectConfig.getProjectMap().get(student.getGradeId() + "_" + student.getSex());
            }
            int prjCount = prjNames.split(",").length;
            summaryResult.setTestPrjTotalCount(prjCount);
            summaryResult.setAddress(student.getAddress());
            summaryResult.setBirthday(student.getBirthday());
            summaryResult.setSex(student.getSex());
            summaryResult.setNation(student.getNation());
        }
        summaryResult.setPlanName(plan.getName());
        summaryResult.setSchoolName(school.getName());
        TestResult baseResult = model.getTestResultList().get(0);
        summaryResult.setClassesName(baseResult.getClassesName());
        summaryResult.setGradeId(baseResult.getGradeId());
        summaryResult.setSchoolId(schoolId);
        summaryResult.setName(baseResult.getName());
        summaryResult.setStudyCode(model.getStudyCode());
        summaryResult.setPlanId(plan.getId());

        Map<String, List<TestResult>> stdTestResultPrjMap = model.getTestResultList().stream().collect(Collectors.groupingBy(TestResult::getPrjName));
        if (stdTestResultPrjMap.containsKey("身高") && stdTestResultPrjMap.containsKey("体重")) {
            summaryResult.setTestEndPrjCount(stdTestResultPrjMap.size() - 2);
        } else {
            summaryResult.setTestEndPrjCount(stdTestResultPrjMap.size());
        }
        summaryResult.setTestEndFlag(Objects.equals(summaryResult.getTestPrjTotalCount(), summaryResult.getTestEndPrjCount()));

        AtomicReference<BigDecimal> finalScore = new AtomicReference<>(BigDecimal.ZERO);
        model.getTestResultList().forEach(testResult -> {
            if(testResult.getFinalScore() != null){
                finalScore.set(finalScore.get().add(testResult.getFinalScore()));
            }
        });

        summaryResult.setTestResultList(model.getTestResultList());
        summaryResult.setTotalScore(finalScore.get().setScale(1,RoundingMode.HALF_UP));

        buildTotalScoreLevel(summaryResult,totalScoreStandards);

        summaryResult.setUpdateTime(LocalDateTime.now());
        summaryResultList.add(summaryResult);


        return saveOrUpdateBatch(summaryResultList);
     }

    @Override
    public void updateStudentInfo(Integer planId) {
        this.baseMapper.updateStudentInfo(planId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearSummaryResult(TestResult testResult) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SummaryResult::getPlanId, testResult.getPlanId());
        if (StringUtils.hasLength(testResult.getStudyCode())) {
            wrapper.lambda().eq(SummaryResult::getStudyCode, testResult.getStudyCode());
        }
        if (testResult.getSchoolId() != null) {
            wrapper.lambda().eq(SummaryResult::getSchoolId, testResult.getSchoolId());
        }
        List<SummaryResult> summaryResultList = list(wrapper);
        summaryResultList.forEach(summaryResult -> {
            summaryResult.setTestResultList(new ArrayList<>());
        });
        saveOrUpdateBatch(summaryResultList);
    }

    @Override
    public SummaryResult queryStudyCodeAndPlanId(String studyCode, Integer planId) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SummaryResult::getPlanId, planId);
        wrapper.lambda().eq(SummaryResult::getStudyCode, studyCode);
        return getOne(wrapper);
    }

    @Override
    public List<SummaryResult> queryStudyCodesAndPlanId(List<String> studyCodeList, Integer planId) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SummaryResult::getPlanId, planId);
        wrapper.lambda().in(SummaryResult::getStudyCode, studyCodeList);
        return list(wrapper);
    }

    @Override
    public boolean batchSummaryResult(List<TestResult> uploadResultList) {
        Integer planId = uploadResultList.get(0).getPlanId();
        Map<Integer, List<TestResult>> resultMap = uploadResultList.stream().collect(Collectors.groupingBy(TestResult::getSchoolId));
        List<SummaryResult> summaryResultList = new ArrayList<>();
        Plan plan = planService.getById(planId);
        List<TotalScoreStandard> totalScoreStandards = totalScoreStandardService.listByTemplateId(plan.getTemplateId());
        resultMap.forEach((schoolId, resultList) -> {
            School school = schoolService.getById(schoolId);
            Set<String> studyCodes = resultList.stream().map(TestResult::getStudyCode).collect(Collectors.toSet());
            List<PlanStudent> studentList = planStudentService.queryByPlanIdAndStudyCodes(planId, studyCodes);
            Map<String, PlanStudent> studentMap = studentList.stream().collect(Collectors.toMap(PlanStudent::getStudyCode, s -> s));
            Map<String, List<TestResult>> testResultMap = resultList.stream().collect(Collectors.groupingBy(TestResult::getStudyCode));

            List<PlanApplyProject> planApplyProjects = planApplyProjectService.queryByPlanIdAndStudyCodes(plan.getId(),studyCodes);
            Map<String,List<PlanApplyProject>> planApplyProjectMap = planApplyProjects.stream().collect(Collectors.groupingBy(PlanApplyProject::getStudyCode));
            List<SummaryResult> oldSummaryResult = selectByPlanIdAndStudyCodes(planId, studyCodes);
            Map<String, SummaryResult> summaryResultMap = oldSummaryResult.stream().collect(Collectors.toMap(SummaryResult::getStudyCode, s -> s));

            testResultMap.forEach((studyCode, testResultList) -> {
                PlanStudent student = studentMap.getOrDefault(studyCode, null);
                SummaryResult summaryResult = summaryResultMap.getOrDefault(studyCode, new SummaryResult());
                if (student != null) {
                    List<PlanApplyProject> stdPlanApplyProjects = planApplyProjectMap.get(studyCode);
                    String prjNames = "";
                    if(!CollectionUtils.isEmpty(stdPlanApplyProjects)){
                        prjNames = stdPlanApplyProjects.get(0).getProjectNames();
                    } else {
                        prjNames = testProjectConfig.getProjectMap().get(student.getGradeId() + "_" + student.getSex());
                    }
                    int prjCount = prjNames.split(",").length;
                    summaryResult.setTestPrjTotalCount(prjCount);
                    summaryResult.setAddress(student.getAddress());
                    summaryResult.setBirthday(student.getBirthday());
                    summaryResult.setSex(student.getSex());
                    summaryResult.setNation(student.getNation());
                }
                summaryResult.setPlanName(plan.getName());
                summaryResult.setSchoolName(school.getName());
                TestResult baseResult = testResultList.get(0);
                summaryResult.setClassesName(baseResult.getClassesName());
                summaryResult.setGradeId(baseResult.getGradeId());
                summaryResult.setSchoolId(schoolId);
                summaryResult.setName(baseResult.getName());
                summaryResult.setStudyCode(studyCode);
                summaryResult.setPlanId(planId);

                Map<String, List<TestResult>> stdTestResultPrjMap = testResultList.stream().collect(Collectors.groupingBy(TestResult::getPrjName));
                if (stdTestResultPrjMap.containsKey("身高") && stdTestResultPrjMap.containsKey("体重")) {
                    summaryResult.setTestEndPrjCount(stdTestResultPrjMap.size() - 2);
                } else {
                    summaryResult.setTestEndPrjCount(stdTestResultPrjMap.size());
                }
                summaryResult.setTestEndFlag(summaryResult.getTestPrjTotalCount() == stdTestResultPrjMap.size());

                AtomicReference<BigDecimal> finalScore = new AtomicReference<>(BigDecimal.ZERO);
                testResultList.forEach(testResult -> {
                    if(testResult.getFinalScore() != null){
                        finalScore.set(finalScore.get().add(testResult.getFinalScore()));
                    }
                });

                summaryResult.setTestResultList(testResultList);
                summaryResult.setTotalScore(finalScore.get().setScale(1,RoundingMode.HALF_UP));

                buildTotalScoreLevel(summaryResult,totalScoreStandards);

                summaryResultList.add(summaryResult);
            });
        });

        return saveOrUpdateBatch(summaryResultList);
    }

    private void buildTotalScoreLevel(SummaryResult summaryResult, List<TotalScoreStandard> totalScoreStandards) {
        if (summaryResult.getTotalScore() == null) {
            return;
        }

        // 按分数从高到低排序
        totalScoreStandards.sort((a, b) -> b.getScore().compareTo(a.getScore()));

        for (TotalScoreStandard standard : totalScoreStandards) {
            if (summaryResult.getTotalScore().compareTo(standard.getScore()) >= 0) {
                summaryResult.setTotalLevel(standard.getLevel());
                if (standard.getConvertScore() != null) {
                    summaryResult.setTotalScore(standard.getConvertScore());
                }
                break;
            }
        }
    }

    @Override
    public Page<SummaryResult> getPage(CommonPage<SummaryResult> queryPage) {
        SummaryResult queryParam = queryPage.getQueryParam();
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        if (queryParam.getSchoolId() != null) {
            wrapper.lambda().eq(SummaryResult::getSchoolId, queryParam.getSchoolId());
        }
        if (StringUtils.hasLength(queryParam.getName())) {
            wrapper.lambda().eq(SummaryResult::getName, queryParam.getName());
        }
        if (StringUtils.hasLength(queryParam.getStudyCode())) {
            wrapper.lambda().eq(SummaryResult::getStudyCode, queryParam.getStudyCode());
        }
        if (StringUtils.hasLength(queryParam.getSex())) {
            wrapper.lambda().eq(SummaryResult::getSex, queryParam.getSex());
        }
        if (queryParam.getGradeId() != null) {
            wrapper.lambda().eq(SummaryResult::getGradeId, queryParam.getGradeId());
        }
        if (StringUtils.hasLength(queryParam.getTestQueryDate())) {
            LocalDate queryDate = LocalDate.parse(queryParam.getTestQueryDate() + " 00:00:00",timeFormatter);
            LocalDate endDate = queryDate.plusDays(1);
            wrapper.lambda().ge(SummaryResult::getUpdateTime,queryDate);
            wrapper.lambda().lt(SummaryResult::getUpdateTime,endDate);
        }
        if (queryParam.getDownloadGradeId() != null) {
            if (queryParam.getDownloadGradeId() <= 16) {
                wrapper.lambda().le(SummaryResult::getGradeId, queryParam.getDownloadGradeId());
            } else {
                wrapper.lambda().ge(SummaryResult::getGradeId, queryParam.getDownloadGradeId());
            }
        }
        wrapper.lambda().eq(SummaryResult::getPlanId, queryParam.getPlanId());
        wrapper.lambda().orderByAsc(SummaryResult::getGradeId).orderByAsc(SummaryResult::getClassesName);

        Page<SummaryResult> testResultPage = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
        page(testResultPage, wrapper);
        buildRecords(testResultPage.getRecords());
        return testResultPage;
    }

    @Override
    public List<SummaryResult> getExportList(SummaryResult queryParam) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        if (queryParam.getSchoolId() != null) {
            wrapper.lambda().eq(SummaryResult::getSchoolId, queryParam.getSchoolId());
        }
        if (StringUtils.hasLength(queryParam.getName())) {
            wrapper.lambda().eq(SummaryResult::getName, queryParam.getName());
        }
        if (StringUtils.hasLength(queryParam.getStudyCode())) {
            wrapper.lambda().eq(SummaryResult::getStudyCode, queryParam.getStudyCode());
        }
        if (StringUtils.hasLength(queryParam.getSex())) {
            wrapper.lambda().eq(SummaryResult::getSex, queryParam.getSex());
        }
        if (queryParam.getGradeId() != null) {
            wrapper.lambda().eq(SummaryResult::getGradeId, queryParam.getGradeId());
        }

        if (StringUtils.hasLength(queryParam.getTestQueryDate())) {
            LocalDate queryDate = LocalDate.parse(queryParam.getTestQueryDate() + " 00:00:00",timeFormatter);
            LocalDate endDate = queryDate.plusDays(1);
            wrapper.lambda().ge(SummaryResult::getUpdateTime,queryDate);
            wrapper.lambda().lt(SummaryResult::getUpdateTime,endDate);
        }

        if (queryParam.getDownloadGradeId() != null) {
            if (queryParam.getDownloadGradeId() <= 16) {
                wrapper.lambda().le(SummaryResult::getGradeId, queryParam.getDownloadGradeId());
            } else {
                wrapper.lambda().ge(SummaryResult::getGradeId, queryParam.getDownloadGradeId());
            }
        }

        wrapper.lambda().eq(SummaryResult::getPlanId, queryParam.getPlanId());
        wrapper.lambda().orderByAsc(SummaryResult::getGradeId).orderByAsc(SummaryResult::getClassesName);
        List<SummaryResult> summaryResultList = list(wrapper);
        buildRecords(summaryResultList);
        return summaryResultList;
    }

    @Override
    public List<SummaryResult> listByPlanId(PlanQueryParam planQueryParam) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SummaryResult::getPlanId, planQueryParam.getPlanId());
        if (planQueryParam.getSchoolId() != null) {
            wrapper.lambda().eq(SummaryResult::getSchoolId, planQueryParam.getSchoolId());
        }
        if (planQueryParam.getGradeId() != null) {
            wrapper.lambda().eq(SummaryResult::getGradeId, planQueryParam.getGradeId());
        }
        if(!CollectionUtils.isEmpty(planQueryParam.getStudyCodes())){
            wrapper.lambda().in(SummaryResult::getStudyCode, planQueryParam.getStudyCodes());
        }
        return list(wrapper);
    }

    @Override
    public List<Plan> queryPlanList(SummaryQueryParam queryParam) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().select(SummaryResult::getPlanId);
        wrapper.lambda().eq(SummaryResult::getSchoolId, queryParam.getSchoolId());
        wrapper.lambda().groupBy(SummaryResult::getPlanId);
        List<SummaryResult> summaryResultList = list(wrapper);
        if (CollectionUtils.isEmpty(summaryResultList)) {
            return new ArrayList<>();
        }
        Set<Integer> planIds = summaryResultList.stream().map(SummaryResult::getPlanId).collect(Collectors.toSet());
        return planService.listByIds(planIds);
    }

    @Override
    public Map<String, Object> queryData(SummaryQueryParam queryParam) {
        List<PlanStudent> planStudentList = new ArrayList<>();
        Map<String, Object> summaryMap = new HashMap<>();

        Map<Integer, List<PlanStudent>> gradeStudentMap = new HashMap<>();
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SummaryResult::getSchoolId, queryParam.getSchoolId());
        if (StringUtils.hasLength(queryParam.getSex())) {
            wrapper.lambda().eq(SummaryResult::getSex, queryParam.getSex());
        }
        if (queryParam.getGradeId() != null) {
            wrapper.lambda().eq(SummaryResult::getGradeId, queryParam.getGradeId());
        }
        if (queryParam.getPlanId() != null) {
            wrapper.lambda().eq(SummaryResult::getPlanId, queryParam.getPlanId());
            planStudentList = planStudentService.listForCountByPlanIdAndSchoolId(queryParam.getPlanId(), queryParam.getSchoolId());
            gradeStudentMap = planStudentList.stream().collect(Collectors.groupingBy(PlanStudent::getGradeId));
        }
        List<SummaryResult> summaryResultList = list(wrapper);

        Map<Integer, List<SummaryResult>> gradeSummaryMap = summaryResultList.stream().collect(Collectors.groupingBy(SummaryResult::getGradeId));
        Map<Integer, List<PlanStudent>> finalGradeStudentMap = gradeStudentMap;
        List<SummaryModel> gradeSummaryModels = buildGradeSummaryData(gradeSummaryMap, finalGradeStudentMap);
        summaryMap.put("grade", gradeSummaryModels);
        Collection<SummaryModel> projectSummaryModels = buildProjectSummaryData(summaryResultList, planStudentList, queryParam.getPlanId());
        summaryMap.put("project", projectSummaryModels.stream().filter(summaryModel -> !summaryModel.getDataKey().equals("summary")));
        summaryMap.put("summary", projectSummaryModels.stream().filter(summaryModel -> summaryModel.getDataKey().equals("summary")).findFirst().orElse(new SummaryModel()));
        return summaryMap;
    }

    private Collection<SummaryModel> buildProjectSummaryData(List<SummaryResult> summaryResultList, List<PlanStudent> planStudentList, Integer planId) {

        Plan plan = planService.getById(planId);
        Integer templateId = plan.getTemplateId();
        List<SysHealthProject> templateProjectList = projectService.listByTemplateId(templateId);
        Map<String,List<SysHealthProject>> projectMap = templateProjectList.stream().collect(Collectors.groupingBy(SysHealthProject::getGradeId));

        List<String> studyCodes = summaryResultList.parallelStream().map(SummaryResult::getStudyCode).collect(Collectors.toList());
        Map<String,PlanApplyProject> applyProjectMap;
        if(!CollectionUtils.isEmpty(studyCodes)){
            List<PlanApplyProject> applyProjects = planApplyProjectService.queryByPlanIdAndStudyCodes(planId,studyCodes);
            applyProjectMap = applyProjects.stream().collect(Collectors.toMap(PlanApplyProject::getStudyCode, p -> p));
        } else {
            applyProjectMap = new HashMap<>();
        }


        CountModel countModel = buildCount(planStudentList,summaryResultList);

        Map<String, SummaryModel> projectSummaryMap = new HashMap<>();
        AtomicInteger bestTotalCount = new AtomicInteger();
        AtomicInteger femaleBestCount = new AtomicInteger();
        AtomicInteger maleBestCount = new AtomicInteger();
        AtomicInteger wellTotalCount = new AtomicInteger();
        AtomicInteger femaleWellCount = new AtomicInteger();
        AtomicInteger maleWellCount = new AtomicInteger();
        AtomicInteger passTotalCount = new AtomicInteger();
        AtomicInteger femalePassCount = new AtomicInteger();
        AtomicInteger malePassCount = new AtomicInteger();
        AtomicInteger noPassTotalCount = new AtomicInteger();
        AtomicInteger femaleNoPassCount = new AtomicInteger();
        AtomicInteger maleNoPassCount = new AtomicInteger();
        SummaryModel summaryTotalModel = new SummaryModel();
        summaryTotalModel.setDataKey("summary");
        summaryTotalModel.setPrjCode("summary");
        summaryResultList.forEach(summaryResult -> {
            if(StringUtils.hasLength(summaryResult.getTotalLevel())){
                if (summaryResult.getTotalLevel().equalsIgnoreCase("优秀")) {
                    bestTotalCount.getAndIncrement();
                    if(summaryResult.getSex().equals("1")){
                        maleBestCount.getAndIncrement();
                    }else{
                        femaleBestCount.getAndIncrement();
                    }
                } else if (summaryResult.getTotalLevel().equalsIgnoreCase("良好")) {
                    wellTotalCount.getAndIncrement();
                    if(summaryResult.getSex().equals("1")){
                        maleWellCount.getAndIncrement();
                    }else{
                        femaleWellCount.getAndIncrement();
                    }
                } else if (summaryResult.getTotalLevel().equalsIgnoreCase("及格")) {
                    passTotalCount.getAndIncrement();
                    if(summaryResult.getSex().equals("1")){
                        malePassCount.getAndIncrement();
                    }else{
                        femalePassCount.getAndIncrement();
                    }
                } else {
                    noPassTotalCount.getAndIncrement();
                    if(summaryResult.getSex().equals("1")){
                        maleNoPassCount.getAndIncrement();
                    }else{
                        femaleNoPassCount.getAndIncrement();
                    }
                }
            }
            List<TestResult> testResultList = summaryResult.getTestResultList();
            Map<String,List<TestResult>> testResultMap = testResultList.stream().collect(Collectors.groupingBy(TestResult::getPrjName));
            List<SysHealthProject> projectList = projectMap.getOrDefault(summaryResult.getGradeId().toString(),null);
            projectList.forEach(projectModel -> {
                //肺活量
                SummaryModel summaryModel = projectSummaryMap.get(projectModel.getProjectName());
                if (summaryModel == null) {
                    summaryModel = new SummaryModel();
                    summaryModel.setDataKey(projectModel.getProjectName());
                    summaryModel.setTotalCount(0);
                    summaryModel.setFreeTestCount(0);
                    summaryModel.setPrjCode(projectModel.getProjectName());
                    summaryModel.setTestCount(0);
                }
                List<TestResult> testResults = testResultMap.getOrDefault(projectModel.getProjectName(),null);
                if(plan.getExamFlag()){
                    PlanApplyProject applyProject = applyProjectMap.getOrDefault(summaryResult.getStudyCode(),null);
                    if(applyProject != null){
                        // 根据性别过滤项目
                        boolean shouldCount = true;
                        String projectName = projectModel.getProjectName();
                        String sex = summaryResult.getSex();
                        
                        // 女生项目
                        if ((projectName.contains("800米") || projectName.contains("仰卧起坐")) && "1".equals(sex)) {
                            shouldCount = false;
                        }
                        // 男生项目
                        if ((projectName.contains("1000米") || projectName.contains("引体向上")) && "2".equals(sex)) {
                            shouldCount = false;
                        }

                        if (shouldCount && applyProject.getProjectNames().contains(projectModel.getProjectName())) {
                            summaryModel.setTotalCount(summaryModel.getTotalCount() + 1);
                        }
                    }
                } else {
                    // 根据性别过滤项目
                    boolean shouldCount = true;
                    String projectName = projectModel.getProjectName();
                    String sex = summaryResult.getSex();
                    
                    // 女生项目
                    if ((projectName.contains("800米") || projectName.contains("仰卧起坐")) && "1".equals(sex)) {
                        shouldCount = false;
                    }
                    // 男生项目
                    if ((projectName.contains("1000米") || projectName.contains("引体向上")) && "2".equals(sex)) {
                        shouldCount = false;
                    }

                    if (shouldCount) {
                        summaryModel.setTotalCount(summaryModel.getTotalCount() + 1);
                    }
                }
                if(!CollectionUtils.isEmpty(testResults)){
                    TestResult testResult = testResults.get(0);
                    // 根据性别过滤项目
                    boolean shouldCount = true;
                    String projectName = testResult.getPrjName();
                    String sex = summaryResult.getSex();
                    
                    // 女生项目
                    if ((projectName.contains("800米") || projectName.contains("仰卧起坐")) && "1".equals(sex)) {
                        shouldCount = false;
                    }
                    // 男生项目
                    if ((projectName.contains("1000米") || projectName.contains("引体向上")) && "2".equals(sex)) {
                        shouldCount = false;
                    }

                    if (shouldCount) {
                        if (StringUtils.hasLength(testResult.getResult())) {
                            summaryModel.setTestCount(summaryModel.getTestCount() + 1);
                        } else {
                            summaryModel.setFreeTestCount(summaryModel.getFreeTestCount() + 1);
                        }
                        String level = testResult.getLevel();
                        if(StringUtils.hasLength(level)){
                            if (testResult.getPrjName().equalsIgnoreCase("BMI")) {
                                switch (level) {
                                    case "正常":
                                        summaryModel.setBestCount(summaryModel.getBestCount() + 1);
                                        break;
                                    case "低体重":
                                        summaryModel.setWellCount(summaryModel.getWellCount() + 1);
                                        break;
                                    case "超重":
                                        summaryModel.setPassCount(summaryModel.getPassCount() + 1);
                                        break;
                                    case "肥胖":
                                        summaryModel.setNoPassCount(summaryModel.getNoPassCount() + 1);
                                        break;
                                }
                            } else {
                                switch (level) {
                                    case "优秀":
                                        summaryModel.setBestCount(summaryModel.getBestCount() + 1);
                                        break;
                                    case "良好":
                                        summaryModel.setWellCount(summaryModel.getWellCount() + 1);
                                        break;
                                    case "及格":
                                        summaryModel.setPassCount(summaryModel.getPassCount() + 1);
                                        break;
                                    case "不及格":
                                        summaryModel.setNoPassCount(summaryModel.getNoPassCount() + 1);
                                        break;
                                }
                            }
                        }
                    }
                }
                projectSummaryMap.put(projectModel.getProjectName(), summaryModel);
            });
        });

        projectSummaryMap.values().removeIf(summaryModel -> summaryModel.getTestCount() == 0);
        projectSummaryMap.values().forEach(summaryModel -> {
            // 使用实际参加测试的人数（不包括免考和缺考）作为分母
            int effectiveCount = summaryModel.getTestCount();
            if (effectiveCount > 0) {
                summaryModel.setBestRate(new BigDecimal(summaryModel.getBestCount())
                        .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setWellRate(new BigDecimal(summaryModel.getWellCount())
                        .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setPassRate(new BigDecimal(summaryModel.getPassCount())
                        .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setNoPassRate(new BigDecimal(summaryModel.getNoPassCount())
                        .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setQualifiedRate(summaryModel.getBestRate()
                        .add(summaryModel.getWellRate())
                        .add(summaryModel.getPassRate()));
            }
        });

        // 设置总体统计数据
        summaryTotalModel.setTotalCount(countModel.getTotal());
        summaryTotalModel.setFemaleTotalCount(countModel.getFemaleTotal());
        summaryTotalModel.setMaleTotalCount(countModel.getMaleTotal());

        summaryTotalModel.setFreeTestCount(countModel.getFreeTestTotal());
        summaryTotalModel.setFemaleFreeTestCount(countModel.getFemaleFreeTestTotal());
        summaryTotalModel.setMaleFreeTestCount(countModel.getMaleFreeTestTotal());

        // 计算免考率
        if (countModel.getTotal() > 0) {
            summaryTotalModel.setFreeTestRate(new BigDecimal(countModel.getFreeTestTotal())
                    .divide(new BigDecimal(countModel.getTotal()), 4, RoundingMode.HALF_UP)
                    .multiply(percent));
        }

        summaryTotalModel.setTestCount(countModel.getTestTotal());
        summaryTotalModel.setFemaleTestCount(countModel.getFemaleTestTotal());
        summaryTotalModel.setMaleTestCount(countModel.getMaleTestTotal());

        summaryTotalModel.setBestCount(bestTotalCount.get());
        summaryTotalModel.setFemaleBestCount(femaleBestCount.get());
        summaryTotalModel.setMaleBestCount(maleBestCount.get());

        summaryTotalModel.setWellCount(wellTotalCount.get());
        summaryTotalModel.setFemaleWellCount(femaleWellCount.get());
        summaryTotalModel.setMaleWellCount(maleWellCount.get());

        summaryTotalModel.setPassCount(passTotalCount.get());
        summaryTotalModel.setFemalePassCount(femalePassCount.get());
        summaryTotalModel.setMalePassCount(malePassCount.get());

        summaryTotalModel.setNoPassCount(noPassTotalCount.get());
        summaryTotalModel.setFemaleNoPassCount(femaleNoPassCount.get());
        summaryTotalModel.setMaleNoPassCount(maleNoPassCount.get());

        // 计算总体各项比率，使用实际参加测试的人数作为分母
        if (countModel.getTestTotal() > 0) {
            BigDecimal effectiveCount = new BigDecimal(countModel.getTestTotal());
            summaryTotalModel.setBestRate(new BigDecimal(bestTotalCount.get())
                    .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                    .multiply(percent));
            summaryTotalModel.setWellRate(new BigDecimal(wellTotalCount.get())
                    .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                    .multiply(percent));
            summaryTotalModel.setPassRate(new BigDecimal(passTotalCount.get())
                    .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                    .multiply(percent));
            summaryTotalModel.setNoPassRate(new BigDecimal(noPassTotalCount.get())
                    .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                    .multiply(percent));
            summaryTotalModel.setQualifiedRate(summaryTotalModel.getBestRate()
                    .add(summaryTotalModel.getWellRate())
                    .add(summaryTotalModel.getPassRate()));
        }

        projectSummaryMap.put("summary", summaryTotalModel);
        return projectSummaryMap.values();
    }

    private List<SummaryModel> buildGradeSummaryData(Map<Integer, List<SummaryResult>> gradeSummaryMap, Map<Integer, List<PlanStudent>> finalGradeStudentMap) {
        List<SummaryModel> gradeSummaryModels = new ArrayList<>();
        gradeSummaryMap.forEach((gradeId, summaryList) -> {
            SummaryModel summaryModel = new SummaryModel();
            summaryModel.setId(gradeId.toString());
            summaryModel.setDataKey(GradeUtil.getGradeName(gradeId));
            summaryModel.setPrjCode(gradeId.toString());
            List<PlanStudent> studentList = finalGradeStudentMap.getOrDefault(gradeId, new ArrayList<>());
            Map<String, List<PlanStudent>> classMap = studentList.stream().collect(Collectors.groupingBy(PlanStudent::getClassesName));

            CountModel countModel = buildCount(studentList,summaryList);

            summaryModel.setTestCount(countModel.getTestTotal());
            summaryModel.setTotalCount(studentList.size());
            summaryModel.setMaleTotalCount(countModel.getMaleTotal());
            summaryModel.setFemaleTotalCount(countModel.getFemaleTotal());
            summaryModel.setFreeTestCount(countModel.getFreeTestTotal());
            summaryModel.setMaleFreeTestCount(countModel.getMaleFreeTestTotal());
            summaryModel.setFemaleFreeTestCount(countModel.getFemaleFreeTestTotal());

            AtomicInteger bestCount = new AtomicInteger(0);
            AtomicInteger femaleBestCount = new AtomicInteger(0);
            AtomicInteger maleBestCount = new AtomicInteger(0);
            AtomicInteger wellCount = new AtomicInteger(0);
            AtomicInteger femaleWellCount = new AtomicInteger(0);
            AtomicInteger maleWellCount = new AtomicInteger(0);
            AtomicInteger passCount = new AtomicInteger(0);
            AtomicInteger femalePassCount = new AtomicInteger(0);
            AtomicInteger malePassCount = new AtomicInteger(0);
            AtomicInteger noPassCount = new AtomicInteger(0);
            AtomicInteger femaleNoPassCount = new AtomicInteger(0);
            AtomicInteger maleNoPassCount = new AtomicInteger(0);
            Map<String,SummaryModel> classesSummaryModelMap = new HashMap<>();
            summaryList.forEach(summaryResult -> {
                if(StringUtils.hasLength(summaryResult.getTotalLevel())){
                    if (summaryResult.getTotalLevel().equalsIgnoreCase("优秀")) {
                        bestCount.getAndIncrement();
                        if(summaryResult.getSex().equals("1")){
                            maleBestCount.getAndIncrement();
                        }else{
                            femaleBestCount.getAndIncrement();
                        }
                    } else if (summaryResult.getTotalLevel().equalsIgnoreCase("良好")) {
                        wellCount.getAndIncrement();
                        if(summaryResult.getSex().equals("1")){
                            maleWellCount.getAndIncrement();
                        }else{
                            femaleWellCount.getAndIncrement();
                        }
                    } else if (summaryResult.getTotalLevel().equalsIgnoreCase("及格")) {
                        passCount.getAndIncrement();
                        if(summaryResult.getSex().equals("1")){
                            malePassCount.getAndIncrement();
                        }else{
                            femalePassCount.getAndIncrement();
                        }
                    } else {
                        noPassCount.getAndIncrement();
                        if(summaryResult.getSex().equals("1")){
                            maleNoPassCount.getAndIncrement();
                        }else{
                            femaleNoPassCount.getAndIncrement();
                        }
                    }
                }
                buildClassesSummaryModel(summaryResult,countModel.getFreeTestStudentMap(),classesSummaryModelMap,classMap);
            });
            summaryModel.setBestCount(bestCount.get());
            summaryModel.setFemaleBestCount(femaleBestCount.get());
            summaryModel.setMaleBestCount(maleBestCount.get());

            summaryModel.setWellCount(wellCount.get());
            summaryModel.setFemaleWellCount(femaleWellCount.get());
            summaryModel.setMaleWellCount(maleWellCount.get());

            summaryModel.setPassCount(passCount.get());
            summaryModel.setFemalePassCount(femalePassCount.get());
            summaryModel.setMalePassCount(malePassCount.get());

            summaryModel.setNoPassCount(noPassCount.get());
            summaryModel.setFemaleNoPassCount(femaleNoPassCount.get());
            summaryModel.setMaleNoPassCount(maleNoPassCount.get());

            summaryModel.setClassesSummaryList(buildClassesRate(classesSummaryModelMap.values()));

            // 使用实际参加测试的人数（不包括免考和缺考）作为分母
            if (countModel.getTestTotal() > 0) {
                BigDecimal effectiveCount = new BigDecimal(countModel.getTestTotal());
                summaryModel.setBestRate(new BigDecimal(bestCount.get())
                        .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setWellRate(new BigDecimal(wellCount.get())
                        .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setPassRate(new BigDecimal(passCount.get())
                        .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setNoPassRate(new BigDecimal(noPassCount.get())
                        .divide(effectiveCount, 4, RoundingMode.HALF_UP)
                        .multiply(percent));
                summaryModel.setQualifiedRate(summaryModel.getBestRate()
                        .add(summaryModel.getWellRate())
                        .add(summaryModel.getPassRate()));
            }
            gradeSummaryModels.add(summaryModel);
        });
        return gradeSummaryModels;
    }

    private CountModel buildCount(List<PlanStudent> studentList, List<SummaryResult> summaryResultList) {
        CountModel countModel = new CountModel();
        Map<String, PlanStudent> studentMap = new HashMap<>();
        Map<String, PlanStudent> freeTestStudentMap = new HashMap<>();

        // 将成绩结果转换为Map，方便查找
        Map<String, SummaryResult> summaryResultMap = summaryResultList.stream()
                .collect(Collectors.toMap(SummaryResult::getStudyCode, s -> s));

        // 统计所有学生
        studentList.forEach(planStudent -> {
            String studyCode = planStudent.getStudyCode();
            SummaryResult summaryResult = summaryResultMap.get(studyCode);
            
            // 更新总人数统计
            countModel.setTotal(countModel.getTotal() + 1);
            if (planStudent.getSex().equals("1")) {
                countModel.setMaleTotal(countModel.getMaleTotal() + 1);
            } else {
                countModel.setFemaleTotal(countModel.getFemaleTotal() + 1);
            }

            // 如果在成绩表中不存在，则为缺考
            if (summaryResult == null) {
                return;
            }

            // 判断是否有任何一项成绩不为空（实测）
            boolean hasValidResult = false;
            if (!CollectionUtils.isEmpty(summaryResult.getTestResultList())) {
                for (TestResult testResult : summaryResult.getTestResultList()) {
                    if (StringUtils.hasLength(testResult.getResult())) {
                        hasValidResult = true;
                        break;
                    }
                }
            }

            // 更新免考和实测人数统计
            if (!hasValidResult) {
                countModel.setFreeTestTotal(countModel.getFreeTestTotal() + 1);
                if (planStudent.getSex().equals("1")) {
                    countModel.setMaleFreeTestTotal(countModel.getMaleFreeTestTotal() + 1);
                } else {
                    countModel.setFemaleFreeTestTotal(countModel.getFemaleFreeTestTotal() + 1);
                }
                freeTestStudentMap.put(studyCode, planStudent);
            } else {
                countModel.setTestTotal(countModel.getTestTotal() + 1);
                if (planStudent.getSex().equals("1")) {
                    countModel.setMaleTestTotal(countModel.getMaleTestTotal() + 1);
                } else {
                    countModel.setFemaleTestTotal(countModel.getFemaleTestTotal() + 1);
                }
                studentMap.put(studyCode, planStudent);
            }
        });

        countModel.setStudentMap(studentMap);
        countModel.setFreeTestStudentMap(freeTestStudentMap);
        return countModel;
    }

    private Collection<SummaryModel> buildClassesRate(Collection<SummaryModel> summaryModels) {
        if (!CollectionUtils.isEmpty(summaryModels)) {
            summaryModels.forEach(summaryModel -> {
                // 使用实际参加测试的人数（不包括免考和缺考）作为分母
                int effectiveCount = summaryModel.getTestCount();
                if (effectiveCount > 0) {
                    summaryModel.setBestRate(new BigDecimal(summaryModel.getBestCount())
                            .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                            .multiply(percent));
                    summaryModel.setWellRate(new BigDecimal(summaryModel.getWellCount())
                            .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                            .multiply(percent));
                    summaryModel.setPassRate(new BigDecimal(summaryModel.getPassCount())
                            .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                            .multiply(percent));
                    summaryModel.setNoPassRate(new BigDecimal(summaryModel.getNoPassCount())
                            .divide(new BigDecimal(effectiveCount), 4, RoundingMode.HALF_UP)
                            .multiply(percent));
                    summaryModel.setQualifiedRate(summaryModel.getBestRate()
                            .add(summaryModel.getWellRate())
                            .add(summaryModel.getPassRate()));
                }
            });
        }
        return summaryModels;
    }


    /**
     * 构建班级的统计数据
     * @param summaryResult 年级data
     */
    private void buildClassesSummaryModel(SummaryResult summaryResult,Map<String,PlanStudent> freeTestStudentMap,Map<String,SummaryModel> summaryModelMap,Map<String, List<PlanStudent>> classMap) {
        SummaryModel summaryModel = summaryModelMap.getOrDefault(summaryResult.getClassesName(),null);
        if(summaryModel == null){
            summaryModel = new SummaryModel();
            summaryModel.setParentId(summaryResult.getGradeId().toString());
            summaryModel.setDataKey(summaryResult.getClassesName());
            Integer classStdNum = classMap.getOrDefault(summaryResult.getClassesName(),new ArrayList<>()).size();
            summaryModel.setTotalCount(classStdNum);
        }

        AtomicBoolean freeTestFlag = new AtomicBoolean(true);
        if (!CollectionUtils.isEmpty(summaryResult.getTestResultList())) {
            for (TestResult testResult : summaryResult.getTestResultList()) {
                if (StringUtils.hasLength(testResult.getResult())) {
                    freeTestFlag.set(false);
                    break;
                }
            }
        } else {
            freeTestFlag.set(false);
        }

        if(!freeTestFlag.get()){
            summaryModel.setTestCount(summaryModel.getTestCount() + 1);
        } else {
            summaryModel.setFreeTestCount(summaryModel.getFreeTestCount() + 1);
            if(summaryResult.getSex().equals("1")){
                summaryModel.setMaleFreeTestCount(summaryModel.getMaleFreeTestCount() + 1);
            }else{
                summaryModel.setFemaleFreeTestCount(summaryModel.getFemaleFreeTestCount() + 1);
            }
        }

        if(StringUtils.hasLength(summaryResult.getTotalLevel())){
            if (summaryResult.getTotalLevel().equalsIgnoreCase("优秀")) {
                summaryModel.setBestCount(summaryModel.getBestCount() + 1);
                if(summaryResult.getSex().equals("1")){
                    summaryModel.setMaleBestCount(summaryModel.getMaleBestCount() + 1);
                }else{
                    summaryModel.setFemaleBestCount(summaryModel.getFemaleBestCount() + 1);
                }
            } else if (summaryResult.getTotalLevel().equalsIgnoreCase("良好")) {
                summaryModel.setWellCount(summaryModel.getWellCount() + 1);
                if(summaryResult.getSex().equals("1")){
                    summaryModel.setMaleWellCount(summaryModel.getMaleWellCount() + 1);
                }else{
                    summaryModel.setFemaleWellCount(summaryModel.getFemaleWellCount() + 1);
                }
            } else if (summaryResult.getTotalLevel().equalsIgnoreCase("及格")) {
                summaryModel.setPassCount(summaryModel.getPassCount() + 1);
                if(summaryResult.getSex().equals("1")){
                    summaryModel.setMalePassCount(summaryModel.getMalePassCount() + 1);
                }else{
                    summaryModel.setFemalePassCount(summaryModel.getFemalePassCount() + 1);
                }
            } else {
                summaryModel.setNoPassCount(summaryModel.getNoPassCount() + 1);
                if(summaryResult.getSex().equals("1")){
                    summaryModel.setMaleNoPassCount(summaryModel.getMaleNoPassCount() + 1);
                }else{
                    summaryModel.setFemaleNoPassCount(summaryModel.getFemaleNoPassCount() + 1);
                }
            }
        }

        summaryModel.setMissExamCount(summaryModel.getTotalCount() - summaryModel.getTestCount() - summaryModel.getFreeTestCount());

        summaryModelMap.put(summaryResult.getClassesName(),summaryModel);

    }

    private List<SummaryResult> selectByPlanIdAndStudyCodes(Integer planId, Collection<String> studyCodes) {
        QueryWrapper<SummaryResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SummaryResult::getPlanId, planId);
        wrapper.lambda().in(SummaryResult::getStudyCode, studyCodes);
        return list(wrapper);
    }

    private void buildRecords(List<SummaryResult> records) {
        if (!CollectionUtils.isEmpty(records)) {
            Set<Integer> schoolIds = new HashSet<>();
            records.forEach(rec -> {
                schoolIds.add(rec.getSchoolId());
            });

            List<School> schoolList = schoolService.listByIds(schoolIds);
            Map<Integer, School> schoolMap = schoolList.stream().collect(Collectors.toMap(School::getId, s -> s));
            records.forEach(rec -> {
                rec.setSchoolName(schoolMap.getOrDefault(rec.getSchoolId(), new School()).getName());
                if(!CollectionUtils.isEmpty(rec.getTestResultList())){
                    rec.getTestResultList().forEach(tr -> {
                        if(tr.getPrjName().equalsIgnoreCase("身高体重")){
                            tr.setPrjName("BMI");
                        }
                    });
                }
            });
        }
    }

}
